package com.yhy.wxzn.wcs.device.plc.siemens;

import HslCommunication.SiemensHelper;
import com.alibaba.fastjson.JSON;
import com.yhy.wxzn.common.utils.PlcGetByte;
import com.yhy.wxzn.common.utils.SpringUtil;
import com.yhy.wxzn.wcs.device.netty.bean.ResultData;
import com.yhy.wxzn.wcs.device.plc.bean.*;
import com.yhy.wxzn.wcs.service.IWcsDeviceInfoService;
import com.yhy.wxzn.wcs.service.IWcsDeviceLogService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.CollectionUtils;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @Auther: 97354
 * @Date: 2023/11/6 16:08
 * @Description: SiemensPlcDriver
 * @Version 1.0.0
 */
//@Component
@Slf4j
public class SiemensPlcDriver extends Thread {

    public  volatile SiemensHelper siemensHelper;
    private volatile String plcIp;
    private volatile int plcType;
    private volatile String plcName;
    private byte rack = 0;
    private byte slot = 0;
    private volatile int deviceConnected = 0;
    public volatile PlcDriverData driverData = new PlcDriverData();
    private IWcsDeviceLogService deviceLogService;
    private IWcsDeviceInfoService deviceInfoService;

    public SiemensPlcDriver(String plcIp,String plcName,int serial,int rack,int slot){
        this.plcIp = plcIp;
        this.plcType = serial;
        this.plcName = plcName;
        this.rack = (byte) rack;
        this.slot = (byte) slot;
        siemensHelper = new SiemensHelper(plcType,this.rack,this.slot);
    }

    private void init() {
        deviceLogService = SpringUtil.getBean(IWcsDeviceLogService.class);
        deviceInfoService = SpringUtil.getBean(IWcsDeviceInfoService.class);
    }

    @Override
    public void run() {
        while (true) {
            try {
                if (SpringUtil.getApplicationContext() != null) {
                    init();
                    break;
                }
                sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        siemensHelper.connect(plcIp);
        connectStatus();
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        executorService.execute(() -> {
            while (true) {
                try {
                    if (!isSuccess()) {
                        log.error("{}离线，暂停同步心跳", plcName);
                        sleep(10000);
                        continue;
                    }
                    //同步心跳
                    synHeartbeat();
                    sleep(100);
                } catch (Exception ex) {
                    log.error("同步心跳处理异常", ex);
                }
            }
        });
        executorService.execute(() -> {
            while (true) {
                try {
                    if (!siemensHelper.isConnectd()) {
                        sleep(10000);
                        continue;
                    }
                    //同步出入库口
                    synPort();
                    sleep(100);
                } catch (Exception ex) {
                    log.error("同步入库口处理异常", ex);
                }
            }
        });
        executorService.execute(() -> {
            while (true) {
                try {
                    if (!siemensHelper.isConnectd()) {
                        sleep(10000);
                        continue;
                    }
                    //同步输送线
                    synTransmission();
                    //按钮信号
//                    synBeatButton();
                    sleep(100);
                } catch (Exception ex) {
                    log.error("同步输送线处理异常", ex);
                }
            }
        });
        executorService.execute(() -> {
            while (true) {
                try {
                    if (!siemensHelper.isConnectd()) {
                        sleep(10000);
                        continue;
                    }
                    //同步提升机
                    synHoist();
                    sleep(100);
                } catch (Exception ex) {
                    log.error("同步提升机处理异常", ex);
                }
            }
        });
//        executorService.execute(() -> {
//            while (true) {
//                try {
//                    if (!siemensHelper.isConnectd()) {
//                        sleep(10000);
//                        continue;
//                    }
//                    //同步拆叠盘机
//                    synStacker();
//                    //同步拆盘机
//                    synDemolish();
//                    //同步叠盘机
//                    synPileup();
//                    sleep(100);
//                } catch (Exception ex) {
//                    log.error("同步拆叠盘机处理异常", ex);
//                }
//            }
//        });
    }

//    private void synPileup() {
//        if (CollectionUtils.isEmpty(plcDataPacket.getPileupReadPlcMap())) {
//            return;
//        }
//        plcDataPacket.getPileupReadPlcMap().entrySet().parallelStream().forEach(pileupPlcEntry -> {
//            String coord = pileupPlcEntry.getKey();
//            StackerPlc pileupPlc = pileupPlcEntry.getValue();
//            if (null == pileupPlc) {
//                return;
//            }
//            ResultData resultData = read(pileupPlc.getReadAddress(), 8, pileupPlc.getRefreshTime());
//            if (resultData.isSuccess()) {
//                byte[] bytes = (byte[]) resultData.getValue();
//                int callOutBound = PlcGetByte.bytesToInt16Hight2(bytes, 0);
//                int qty = PlcGetByte.bytesToInt16Hight2(bytes, 2);
//                int status = PlcGetByte.bytesToInt16Hight2(bytes, 4);
//                int backup = PlcGetByte.bytesToInt16Hight2(bytes, 6);
//
//                String msg = pileupChange(pileupPlc, callOutBound, qty, status, backup);
//
//                if (callOutBound > 0 && callOutBound != pileupPlc.getCallOutBound()) {
//                    pileupPlc.setChange(true);
//                }
//
//                pileupPlc.setCallOutBound(callOutBound);
//                pileupPlc.setQty(qty);
//                pileupPlc.setStatus(status);
//                pileupPlc.setBackup(backup);
//
//                if (StringUtils.isNotEmpty(msg)) {
//                    log.info("同步叠盘机点位{}数据结束，pileupPlc：{}，变化值：{}", coord, JSON.toJSONString(pileupPlc), msg);
//                }
//            } else {
//                String msg = String.format("读取叠盘机点位--%s--地址--%s--数据失败,失败原因为--%s",coord,pileupPlc.getReadAddress(), resultData.getMessage());
//                deviceLogService.genCoordLog(coord,msg);
//            }
//        });
//    }

    public synchronized ResultData write(String address, Object value) {
        ResultData resultData = notConnect();
        if (resultData != null) {
            return resultData;
        }
        if (value instanceof byte[]) {
            resultData = siemensHelper.write(address, (byte[]) value);
        } else if (value instanceof Integer) {
            resultData = siemensHelper.write(address, (int) value);
        } else if (value instanceof Short) {
            resultData = siemensHelper.write(address, (short) value);
        } else if (value instanceof Boolean) {
            resultData = siemensHelper.write(address, (boolean) value);
        } else {
            resultData = new ResultData();
            resultData.setConnecd(false);
            resultData.setSuccess(false);
            resultData.setMessage("地址类型有误！");
        }
        return resultData;
    }

    private String pileupChange(StackerPlc pileupPlc, int callOutBound, int qty, int status, int backup) {
        StringBuilder msg = new StringBuilder();
        if (pileupPlc.getCallOutBound() != callOutBound) {
            msg.append("[CallOutBound：").append(pileupPlc.getCallOutBound()).append("!=").append(callOutBound).append("]，");
        }
        if (pileupPlc.getQty() != qty) {
            msg.append("[Qty：").append(pileupPlc.getQty()).append("!=").append(qty).append("]，");
        }
        if (pileupPlc.getStatus() != status) {
            msg.append("[Status：").append(pileupPlc.getStatus()).append("!=").append(status).append("]，");
        }
        if (pileupPlc.getBackup() != backup) {
            msg.append("[Backup：").append(pileupPlc.getBackup()).append("!=").append(backup).append("]，");
        }
        return msg.toString();
    }

//    private void synDemolish() {
//        if (CollectionUtils.isEmpty(plcDataPacket.getDemolishReadPlcMap())) {
//            return;
//        }
//        plcDataPacket.getDemolishReadPlcMap().entrySet().parallelStream().forEach(demolishPlcEntry -> {
//            String coord = demolishPlcEntry.getKey();
//            StackerPlc demolishPlc = demolishPlcEntry.getValue();
//            if (null == demolishPlc) {
//                return;
//            }
//            ResultData resultData = read(demolishPlc.getReadAddress(), 8, demolishPlc.getRefreshTime());
//            if (resultData.isSuccess()) {
//                byte[] bytes = (byte[]) resultData.getValue();
//                int callInBound = PlcGetByte.bytesToInt16Hight2(bytes, 0);
//                int qty = PlcGetByte.bytesToInt16Hight2(bytes, 2);
//                int status = PlcGetByte.bytesToInt16Hight2(bytes, 4);
//                int backup = PlcGetByte.bytesToInt16Hight2(bytes, 6);
//
//                String msg = demolishChange(demolishPlc, callInBound, qty, status, backup);
//
//                if (callInBound > 0 && callInBound != demolishPlc.getCallInBound()) {
//                    demolishPlc.setChange(true);
//                }
//
//                demolishPlc.setCallInBound(callInBound);
//                demolishPlc.setQty(qty);
//                demolishPlc.setStatus(status);
//                demolishPlc.setBackup(backup);
//
//                if (StringUtils.isNotEmpty(msg)) {
//                    log.info("同步拆盘机点位{}数据结束，demolishPlc：{}，变化值：{}", coord, JSON.toJSONString(demolishPlc), msg);
//                }
//            } else {
//                String msg = String.format("读取拆盘机点位--%s--地址--%s--数据失败,失败原因为--%s",coord,demolishPlc.getReadAddress(),resultData.getMessage());
//                deviceLogService.genCoordLog(coord,msg);
//            }
//        });
//    }

//    private String demolishChange(StackerPlc demolishPlc, int callInBound, int qty, int status, int backup) {
//        StringBuilder msg = new StringBuilder();
//        if (demolishPlc.getCallInBound() != callInBound) {
//            msg.append("[CallInBound：").append(demolishPlc.getCallInBound()).append("!=").append(callInBound).append("]，");
//        }
//        if (demolishPlc.getQty() != qty) {
//            msg.append("[Qty：").append(demolishPlc.getQty()).append("!=").append(qty).append("]，");
//        }
//        if (demolishPlc.getStatus() != status) {
//            msg.append("[Status：").append(demolishPlc.getStatus()).append("!=").append(status).append("]，");
//        }
//        if (demolishPlc.getBackup() != backup) {
//            msg.append("[Backup：").append(demolishPlc.getBackup()).append("!=").append(backup).append("]，");
//        }
//        return msg.toString();
//    }

//    private void synStacker() {
//        if (CollectionUtils.isEmpty(plcDataPacket.getStackerReadPlcMap())) {
//            return;
//        }
//        plcDataPacket.getStackerReadPlcMap().entrySet().parallelStream().forEach(stackerPlcEntry -> {
//            String coord = stackerPlcEntry.getKey();
//            StackerPlc stackerPlc = stackerPlcEntry.getValue();
//            if (null == stackerPlc) {
//                return;
//            }
//            Date start = new Date();
//            ResultData resultData = read(stackerPlc.getReadAddress(), 10, stackerPlc.getRefreshTime());
//            Date end = new Date();
//            if (resultData.isSuccess()) {
//                byte[] bytes = (byte[]) resultData.getValue();
//                int callOutBound = PlcGetByte.bytesToInt16Hight2(bytes, 0);
//                int callInBound = PlcGetByte.bytesToInt16Hight2(bytes, 2);
//                int qty = PlcGetByte.bytesToInt16Hight2(bytes, 4);
//                int status = PlcGetByte.bytesToInt16Hight2(bytes, 6);
//                int backup = PlcGetByte.bytesToInt16Hight2(bytes, 8);
//
//                String msg = stackerChange(stackerPlc, callOutBound, callInBound, qty, status, backup);
//
//                if (callOutBound > 0 && callOutBound != stackerPlc.getCallOutBound()) {
//                    stackerPlc.setChange(true);
//                }
//                if (callInBound > 0 && callInBound != stackerPlc.getCallInBound()) {
//                    stackerPlc.setChange(true);
//                }
//
//                stackerPlc.setCallOutBound(callOutBound);
//                stackerPlc.setCallInBound(callInBound);
//                stackerPlc.setQty(qty);
//                stackerPlc.setStatus(status);
//                stackerPlc.setBackup(backup);
//
//                if (StringUtils.isNotEmpty(msg)) {
//                    log.info("同步拆叠盘机点位{}数据结束，stackerPlc：{}，变化值：{}", coord, JSON.toJSONString(stackerPlc), msg);
//                }
//            } else {
//                String msg = String.format("读取拆叠盘机点位--%s--地址--%s--数据失败,失败原因为--%s",coord,stackerPlc.getReadAddress(), resultData.getMessage());
//                deviceLogService.genCoordLog(coord,msg);
//            }
//        });
//    }

//    private String stackerChange(StackerPlc stackerPlc, int callOutBound, int callInBound, int qty, int status, int backup) {
//        StringBuilder msg = new StringBuilder();
//        if (stackerPlc.getCallOutBound() != callOutBound) {
//            msg.append("[CallOutBound：").append(stackerPlc.getCallOutBound()).append("!=").append(callOutBound).append("]，");
//        }
//        if (stackerPlc.getCallInBound() != callInBound) {
//            msg.append("[CallInBound：").append(stackerPlc.getCallInBound()).append("!=").append(callInBound).append("]，");
//        }
//        if (stackerPlc.getQty() != qty) {
//            msg.append("[Qty：").append(stackerPlc.getQty()).append("!=").append(qty).append("]，");
//        }
//        if (stackerPlc.getStatus() != status) {
//            msg.append("[Status：").append(stackerPlc.getStatus()).append("!=").append(status).append("]，");
//        }
//        if (stackerPlc.getBackup() != backup) {
//            msg.append("[Backup：").append(stackerPlc.getBackup()).append("!=").append(backup).append("]，");
//        }
//        return msg.toString();
//    }

    private void synHoist() {
        if (CollectionUtils.isEmpty(driverData.getHoistPlcMap())) {
            return;
        }
        driverData.getHoistPlcMap().entrySet().parallelStream().forEach(hoistPlcEntry -> {
            String hostId = hoistPlcEntry.getKey();
            HoistPlc hoistPlc = hoistPlcEntry.getValue();
            ResultData resultData = read(hoistPlc.getReadAddress(), 22, hoistPlc.getRefreshTime());
            if (resultData.isSuccess()) {
                byte[] bytes = (byte[]) resultData.getValue();
                int deviceNum = PlcGetByte.bytesToInt32Hight(bytes, 0);
                int floor = PlcGetByte.bytesToInt16Hight2(bytes, 4);
                int autoStatus = PlcGetByte.bytesToInt16Hight2(bytes, 6);
                int workStatus = PlcGetByte.bytesToInt16Hight2(bytes, 8);
                int haveStock = PlcGetByte.bytesToInt16Hight2(bytes, 10);
                int haveCar = PlcGetByte.bytesToInt16Hight2(bytes, 12);
                int accessCar = PlcGetByte.bytesToInt16Hight2(bytes, 14);
                int blocker = PlcGetByte.bytesToInt16Hight2(bytes, 16);
                int faultCode = PlcGetByte.bytesToInt16Hight2(bytes, 18);
                int backup = PlcGetByte.bytesToInt16Hight2(bytes, 20);

                String msg = hoistChange(hoistPlc, deviceNum, floor, autoStatus, workStatus, haveStock, haveCar, accessCar, blocker, faultCode, backup);

                hoistPlc.setTaskId(deviceNum);
                hoistPlc.setFloor(floor);
                hoistPlc.setAutoStatus(autoStatus);
                hoistPlc.setWorkStatus(workStatus);
//                hoistPlc.setHaveStock(haveStock);
//                hoistPlc.setHaveCar(haveCar);
//                hoistPlc.setAccessCar(accessCar);
//                hoistPlc.setBlocker(blocker);
                hoistPlc.setFaultCode(faultCode);
                hoistPlc.setBackup(backup);

                if (StringUtils.isNotEmpty(msg)) {
                    log.info("同步提升机{}数据结束，hoistPlc：{}，变化值：{}", hostId, JSON.toJSONString(hoistPlc), msg);
                }
            } else {
                String msg = String.format("读取提升机地址--%s--数据失败,失败原因为--%s", hoistPlc.getReadAddress(), resultData.getMessage());
                deviceLogService.genCoordLog(hostId,msg);
            }
        });
    }

    private String hoistChange(HoistPlc hoistPlc, int deviceNum, int floor, int autoStatus, int workStatus, int haveStock, int haveCar, int accessCar, int blocker, int faultCode, int backup) {
        StringBuilder msg = new StringBuilder();
        if (hoistPlc.getTaskId() != deviceNum) {
            msg.append("[DeviceNum：").append(hoistPlc.getTaskId()).append("!=").append(deviceNum).append("]，");
        }
        if (hoistPlc.getFloor() != floor) {
            msg.append("[Floor：").append(hoistPlc.getFloor()).append("!=").append(floor).append("]，");
        }
        if (hoistPlc.getAutoStatus() != autoStatus) {
            msg.append("[AutoStatus：").append(hoistPlc.getAutoStatus()).append("!=").append(autoStatus).append("]，");
            //故障上报
//            if (autoStatus == 5) {
//                String codeStr = hoistPlc.getHoistId() + " 提升机故障，故障代码：" + faultCode + "，故障描述：" + InitDataListener.faultMap.get(faultCode);
//                mcsAlarmLogService.insertMcsAlarmLog(hoistPlc.getHoistId(), 4, "1", codeStr);
//            }
//            if (hoistPlc.getAutoStatus() == 5) {
//                mcsAlarmLogService.insertMcsAlarmLog(hoistPlc.getHoistId(), 4, "2", hoistPlc.getHoistId() + " 提升机故障恢复");
//            }
        }
        if (hoistPlc.getWorkStatus() != workStatus) {
            msg.append("[WorkStatus：").append(hoistPlc.getWorkStatus()).append("!=").append(workStatus).append("]，");
        }
        if (hoistPlc.getFaultCode() != faultCode) {
            msg.append("[FaultCode：").append(hoistPlc.getFaultCode()).append("!=").append(faultCode).append("]，");
        }
        if (hoistPlc.getBackup() != backup) {
            msg.append("[Backup：").append(hoistPlc.getBackup()).append("!=").append(backup).append("]，");
        }
        return msg.toString();
    }

    private void synTransmission() {
        if (CollectionUtils.isEmpty(driverData.getTransLinePlcMap())) {
            return;
        }
        driverData.getTransLinePlcMap().entrySet().parallelStream().forEach(transLineEntry -> {
            String coord = transLineEntry.getKey();
            TransmissionPlc transmissionPlc = transLineEntry.getValue();
            ResultData resultData = read(transmissionPlc.getReadAddress(), 16, transmissionPlc.getRefreshTime());
            if (resultData.isSuccess()) {
                byte[] bytes = (byte[]) resultData.getValue();
                int deviceNum = PlcGetByte.bytesToInt32Hight(bytes, 0);
                int inPlaceNum = PlcGetByte.bytesToInt16Hight2(bytes, 4);
                int haveStock = PlcGetByte.bytesToInt16Hight2(bytes, 6);
                int status = PlcGetByte.bytesToInt16Hight2(bytes, 8);
                int faultCode = PlcGetByte.bytesToInt16Hight2(bytes, 10);
                int workStatus = PlcGetByte.bytesToInt16Hight2(bytes, 12);
                int backup = PlcGetByte.bytesToInt16Hight2(bytes, 14);

                String msg = transmissionChange(transmissionPlc, deviceNum, inPlaceNum, haveStock, status, faultCode, workStatus, backup);

                transmissionPlc.setDeviceNum(deviceNum);
                transmissionPlc.setInPlaceNum(inPlaceNum);
                transmissionPlc.setHaveStock(haveStock);
                transmissionPlc.setStatus(status);
                transmissionPlc.setFaultCode(faultCode);
                transmissionPlc.setWorkStatus(workStatus);
                transmissionPlc.setBackup(backup);

                if (StringUtils.isNotEmpty(msg)) {
                    log.info("同步输送线点位{}数据结束，transmissionPlc：{}，变化值：{}", coord, JSON.toJSONString(transmissionPlc), msg);
                }
            } else {
                String msg = String.format("读取输送线点位--%s--地址--%s--数据失败,失败原因为--%s",coord,transmissionPlc.getReadAddress(), resultData.getMessage());
                deviceLogService.genCoordLog(coord,msg);
            }
        });
    }

    private String transmissionChange(TransmissionPlc transmissionPlc, int deviceNum, int inPlaceNum, int haveStock, int status, int faultCode, int workStatus, int backup) {
        StringBuilder msg = new StringBuilder();
        if (transmissionPlc.getDeviceNum() != deviceNum) {
            msg.append("[DeviceNum：").append(transmissionPlc.getDeviceNum()).append("!=").append(deviceNum).append("]，");
        }
        if (transmissionPlc.getInPlaceNum() != inPlaceNum) {
            msg.append("[InPlaceNum：").append(transmissionPlc.getInPlaceNum()).append("!=").append(inPlaceNum).append("]，");
        }
        if (transmissionPlc.getHaveStock() != haveStock) {
            msg.append("[HaveStock：").append(transmissionPlc.getHaveStock()).append("!=").append(haveStock).append("]，");
        }
        if (transmissionPlc.getStatus() != status) {
            msg.append("[Status：").append(transmissionPlc.getStatus()).append("!=").append(status).append("]，");
            //故障上报
//            if (status == 5) {
//                String codeStr = transmissionPlc.getDevice() + " 输送线故障，故障代码：" + faultCode + "，故障描述：" + InitDataListener.faultMap.get(faultCode);
//                mcsAlarmLogService.insertMcsAlarmLog(String.valueOf(transmissionPlc.getDevice()), 6, "1", codeStr);
//            }
//            if (transmissionPlc.getStatus() == 5) {
//                mcsAlarmLogService.insertMcsAlarmLog(String.valueOf(transmissionPlc.getDevice()), 6, "2", transmissionPlc.getDevice() + " 输送线故障恢复");
//            }
        }
        if (transmissionPlc.getFaultCode() != faultCode) {
            msg.append("[FaultCode：").append(transmissionPlc.getFaultCode()).append("!=").append(faultCode).append("]，");
        }
        if (transmissionPlc.getWorkStatus() != workStatus) {
            msg.append("[WorkStatus：").append(transmissionPlc.getWorkStatus()).append("!=").append(workStatus).append("]，");
        }
        if (transmissionPlc.getBackup() != backup) {
            msg.append("[Backup：").append(transmissionPlc.getBackup()).append("!=").append(backup).append("]，");
        }
        return msg.toString();
    }

    private void synPort() {
        if (CollectionUtils.isEmpty(driverData.getPortPlcMap())) {
            return;
        }
        driverData.getPortPlcMap().entrySet().parallelStream().forEach(portPlcEntry -> {
            String coord = portPlcEntry.getKey();
            PortPlc portPlc = portPlcEntry.getValue();
            ResultData resultData = read(portPlc.getReadAddress(), 36, portPlc.getRefreshTime());
            if (resultData.isSuccess()) {
                byte[] bytes = (byte[]) resultData.getValue();
                String barCode = PlcGetByte.byteToString(bytes, 0, 16).replace('?', ' ').trim();
                String weight = PlcGetByte.byteToString(bytes, 16, 16).replace('?', ' ').trim();
                int detection = PlcGetByte.bytesToInt16Hight2(bytes, 32);
                int plcNum = PlcGetByte.bytesToInt16Hight2(bytes, 34);

                String msg = portChange(portPlc, barCode, weight, detection, plcNum);

                if (plcNum > 0 && plcNum != portPlc.getPlcNum()) {
                    portPlc.setChange(true);
                }
                portPlc.setBcrCode(barCode);
                portPlc.setWeight(weight);
                portPlc.setDetection(detection);
                portPlc.setPlcNum(plcNum);

                if (StringUtils.isNotEmpty(msg)) {
                    log.info("同步出入库口点位{}数据结束，portPlc：{}，变化值：{}",coord,JSON.toJSONString(portPlc),msg);
                }
            } else {
                String msg = String.format("读取出入库口点位--%s--地址--%s--数据失败,失败原因为--%s",coord,portPlc.getReadAddress(),resultData.getMessage());
                deviceLogService.genCoordLog(coord,msg);
            }
        });
    }

    private String portChange(PortPlc portPlc, String barCode, String weight, int detection, int plcNum) {
        StringBuilder msg = new StringBuilder();
        if (!barCode.equals(portPlc.getBcrCode())) {
            msg.append("[BcrCode：").append(portPlc.getBcrCode()).append("!=").append(barCode).append("]，");
        }
        if (!weight.equals(portPlc.getWeight())) {
            msg.append("[Weight：").append(portPlc.getWeight()).append("!=").append(weight).append("]，");
        }
        if (portPlc.getDetection() != detection) {
            msg.append("[Detection：").append(portPlc.getDetection()).append("!=").append(detection).append("]，");
        }
        if (portPlc.getPlcNum() != plcNum) {
            msg.append("[PlcNum：").append(portPlc.getPlcNum()).append("!=").append(plcNum).append("]，");
        }
        return msg.toString();
    }

    private void synHeartbeat() {
        if (CollectionUtils.isEmpty(driverData.getHeartBeatPlcMap())) {
            return;
        }
        driverData.getHeartBeatPlcMap().entrySet().parallelStream().forEach(heartBeatPlcEntry -> {
            HeartBeatPlc heartBeatPlc = heartBeatPlcEntry.getValue();
            ResultData resultData = read(heartBeatPlc.getReadAddress(), 1, heartBeatPlc.getRefreshTime());
            if (resultData.isSuccess()) {
                short heartbeat = (short) resultData.getValue();
                if (heartBeatPlc.getHeartbeat() != heartbeat) {
                    heartBeatPlc.setChange(true);
                }
                heartBeatPlc.setHeartbeat(heartbeat);
            } else {
                String msg = String.format("读取心跳点位--%s--设备ID--%s--数据失败,失败原因为--%s",heartBeatPlcEntry.getKey(),heartBeatPlc.getReadAddress(),resultData.getMessage());
                deviceLogService.genCoordLog(heartBeatPlcEntry.getKey(),msg);
            }
        });
    }

    public ResultData read(String address, int length, Integer refreshTime) {
        ResultData resultData = notConnect();
        if (resultData != null) {
            return resultData;
        }
        try {
            sleep(refreshTime == null ? 50 : refreshTime);
            return siemensHelper.readBytes(address, length);
        } catch (InterruptedException ex) {
            log.error("读取PLC地址{}异常", address, ex);
            return null;
        }
    }

    public ResultData read(String address, Integer refreshTime) {
        ResultData resultData = notConnect();
        if (resultData != null) {
            return resultData;
        }
        try {
            sleep(refreshTime == null ? 50 : refreshTime);
            if (address.contains("DBX")) {
                return siemensHelper.readBool(address);
            } else if (address.contains("DBW")) {
                return siemensHelper.readShort(address);
            } else if (address.contains("DBD")) {
                return siemensHelper.readInt(address);
            } else {
                resultData = new ResultData();
                resultData.setConnecd(false);
                resultData.setSuccess(false);
                resultData.setMessage("地址类型有误！");
                return resultData;
            }
        } catch (InterruptedException ex) {
            log.error("读取PLC地址{}异常", address, ex);
            return null;
        }
    }

    private ResultData notConnect() {
        if (siemensHelper.isConnectd()) {
            return null;
        }
        ResultData rd = new ResultData();
        rd.setConnecd(false);
        rd.setSuccess(false);
        rd.setMessage("当前与PLC通信断开！");
        return rd;
    }

    private boolean isSuccess() {
        boolean status = siemensHelper.isConnectd();
        if (!status) {
            siemensHelper.close();
            String content = plcName + "：【" + plcIp + " 】重新连接";
            deviceLogService.genCoordLog(plcName,content);
            setAutoByOffline();
            siemensHelper.connect(plcIp);
            connectStatus();
        }
        return status;
    }

    private void setAutoByOffline() {
        driverData.getHoistPlcMap().forEach((k, v) -> v.setAuto(false));
        driverData.getPortPlcMap().forEach((k, v) -> v.setAuto(false));
        driverData.getTransLinePlcMap().forEach((k, v) -> v.setAuto(false));
    }

    private void connectStatus() {
        StringBuffer msg = new StringBuffer();
        if(!siemensHelper.isConnectd() && deviceConnected == 0){
            deviceConnected = 1;
            msg.append("PLC分组号：【"+ plcName + "】IP地址:【" + plcIp + "】 已断开");
        }else if(siemensHelper.isConnectd() && deviceConnected == 0){
            msg.append("PLC分组号：【"+ plcName + "】IP地址:【" + plcIp + "】 已连接");
            deviceConnected = 2;
        }else if(siemensHelper.isConnectd() && deviceConnected == 1){
            deviceConnected = 2;
            msg.append("PLC分组号：【"+ plcName + "】IP地址:【" + plcIp + "】 已连接");
        }else if(!siemensHelper.isConnectd() && deviceConnected == 2){
            msg.append("PLC分组号：【"+ plcName + "】IP地址:【" + plcIp + "】 已断开");
            deviceConnected = 1;
        }
        if(msg.length() > 0){
            deviceLogService.genCoordLog(plcName,msg.toString());
        }
    }

    public synchronized boolean savePlcLog(String address, Object value, Map map) {
        ResultData resultData = write(address, value);
        log.info("{}地址:{}写值结果：{}", plcName, address, JSON.toJSONString(resultData));
        StringBuilder msg = new StringBuilder(String.format("%s号PLC，地址--%s", plcName, address));
        if (resultData.isSuccess()) {
            msg.append(String.format("--写值成功,写值信息为--%s", map.toString()));
            deviceLogService.genCoordLog(address,msg.toString());
        } else {
            msg.append(String.format("--写值失败,失败原因为--%s", resultData.getMessage()));
            deviceLogService.genCoordLog(address,msg.toString());
        }
        return resultData.isSuccess();
    }

    public void reconnect() {
        siemensHelper.close();
        String msg =  plcName + "：【" + plcIp + "】重新连接";
        deviceLogService.genCoordLog(plcName,msg);
        siemensHelper.connect(plcIp);
        connectStatus();
    }

    public PlcDriverData getDriverData() {
        return driverData;
    }
}
